<?php


namespace RedMVC\Model;
use RedMVC;

/**
 * AModelClosureTable class
 *  
 * @category    RedMVC
 * @package     Model
 * @author      Jan Fischer, bitWorking <info@bitworking.de>
 */
abstract class AModelClosureTable extends AModel{
    
    // needs to be overridden
    protected $closureTable = null;
    protected $order        = null;
    protected $label        = null;

    private $_closureTable;
    
    private function setClosureTable(RedMVC\Db\ClosureTable $closureTable){
        $this->_closureTable = $closureTable;
        return $this;
    }
    
    protected function getClosureTable(){
        return $this->_closureTable;
    }
    
    public function init(array $values = null){
        if($this->closureTable === null || $this->order === null || $this->label === null){
            throw new \Exception('AModelClosureTable: $closureTable, $order and $label needs to be overridden');
        }    
        $closureTable = new RedMVC\Db\ClosureTable();
        $closureTable->setup($this->db, $this->closureTable, $this->table, $this->primary, $this->order);
        $this->setClosureTable($closureTable);
        
        $this->fields[] = 'parentId';
        $this->fields[] = 'treeDepth';
        
        if(null !== $values){            
            foreach($values as $key=>$value){                
                $this->$key = $value;
            }
        }
    }
    
    public function addRoot(){
        $this->getClosureTable()->addRoot($this->label);
    }
    
    public function save(){
        $data = $this->toArray();
        unset($data['parentId']);
        unset($data['treeDepth']);
        
        if(array_key_exists($this->primary, $data) && $data[$this->primary] != '' && $data[$this->primary] != null){            
            $id = $data[$this->primary];
            $thisObj = $this->_byId($id);
            if(null === $thisObj->parentId){
                $this->getClosureTable()->save($id, $this->parentId);
            }
            else if($this->parentId != $thisObj->parentId){
                $this->getClosureTable()->update($id, $this->parentId);
            }
            
            $where = array($this->primary=>$data[$this->primary]);
            unset($data[$this->primary]);
            $this->db->update($this->table, $data, $where);            
        }
        else{
            if(isset($data[$this->primary])){
                unset($data[$this->primary]);
            }
            $insertId = $this->db->insert($this->table, $data);
            $this->values[$this->primary] = $insertId;
            $this->getClosureTable()->save($insertId, $this->parentId);
        }
        return $this;
    }

    protected function _byId($id){
        $row = $this->getClosureTable()->byId($id);
        if(null !== $row){
            return new static($row);
        }
        return null;
    }
    
    protected function _delete($id){    
        $this->getClosureTable()->delete($id, true);        
        if($this->db->affectedRows() > 0){
            return true;
        }
        return false;
    }
    
    public static function deleteSubtree($id){
        $class = new static();
        return $class->_deleteSubtree($id);
    }
    
    protected function _deleteSubtree($id){
        $this->getClosureTable()->deleteSubtree($id, true);
        if($this->db->affectedRows() > 0){
            return true;
        }
        return false;
    }
    
    public static function getChilds($id, $includeSelf = false, $whereClauses = array(), $maxTreeDepth = null){
        $class = new static();
        return $class->_getChilds($id, $includeSelf, $whereClauses, $maxTreeDepth);
    }
    
    protected function _getChilds($id, $includeSelf, $whereClauses, $maxTreeDepth){
        $results    = $this->getClosureTable()->getChilds($id, $includeSelf, $whereClauses, $maxTreeDepth);
        $out        = array();
        foreach($results as $result){
            $out[] = new static($result);
        }
        return $out;
    }
    
    public static function getChildsPath($id){
        $class = new static();
        return $class->_getChildsPath($id);
    }
    
    protected function _getChildsPath($id){
        $results    = $this->getClosureTable()->getChildsPath($id, $this->label);
        $out        = array();
        foreach($results as $result){
            $out[] = new static($result);
        }
        return $out;
    }
    
    public static function getFirstChilds($id, $includeSelf = false){
        $class = new static();
        return $class->_getFirstChilds($id, $includeSelf);
    }
    
    protected function _getFirstChilds($id, $includeSelf){
        $results    = $this->getClosureTable()->getFirstChilds($id, $includeSelf);
        $out        = array();
        foreach($results as $result){
            $out[] = new static($result);
        }
        return $out;
    }
    
    public static function getParents($id, $includeSelf = false, $sort = RedMVC\Db\C::SORT_DESC){
        $class = new static();
        return $class->_getParents($id, $includeSelf, $sort);
    }
    
    protected function _getParents($id, $includeSelf, $sort){
        $results    = $this->getClosureTable()->getParents($id, $includeSelf, $sort);
        $out        = array();
        foreach($results as $result){
            $out[] = new static($result);
        }
        return $out;
    }
    
    public static function getParent($id){
        $class = new static();
        return $class->_getParent($id);
    }
    
    protected function _getParent($id){
        $row = $this->getClosureTable()->getParent($id);
        if(null !== $row){
            return new static($row);
        }
        return null;
    }
    
    
}